import { Roles } from "../roles/roles.entity";
import { Logs } from "../logs/logs.entity";
import {
  AfterInsert,
  AfterRemove,
  Column,
  Entity,
  JoinTable,
  ManyToMany,
  OneToMany,
  OneToOne,
  PrimaryGeneratedColumn,
} from "typeorm";
import { Profile } from "./profile.entity";
import { BaseEntity } from "../common/entities/base.entity";
import { Exclude } from "class-transformer";

/**
 * 用户实体类
 *
 * @Entity() 装饰器将此类标记为数据库实体，TypeORM 会自动创建对应的数据库表
 * 表名默认为类名的小写形式，即 'user'
 *
 * 实体类定义了数据库表的结构，包括字段、类型、关系等
 * TypeORM 使用装饰器模式来定义实体的各种属性和关系
 */
@Entity()
export class User extends BaseEntity {
  /**
   * 主键字段 - 用户ID
   *
   * @PrimaryGeneratedColumn() 装饰器的作用：
   * 1. 将此字段标记为主键 (Primary Key)
   * 2. 设置为自动递增 (AUTO_INCREMENT)
   * 3. 数据库会自动为每条新记录生成唯一的ID值
   *
   * 这是实体设计的最佳实践，确保每条记录都有唯一标识
   */
  @PrimaryGeneratedColumn()
  id: number;

  /**
   * 用户名字段
   *
   * @Column() 装饰器将此属性映射为数据库表的列
   * 默认情况下：
   * - 列名与属性名相同
   * - 数据类型根据 TypeScript 类型自动推断 (string -> VARCHAR)
   * - 允许为空值，除非明确设置 nullable: false
   *
   * 生产环境建议添加更多约束，如：
   * @Column({ unique: true, length: 50, nullable: false })
   */
  @Column({ unique: true, nullable: false })
  username: string;

  /**
   * 密码字段
   *
   * 注意：在实际项目中，密码应该：
   * 1. 使用哈希算法加密存储 (如 bcrypt)
   * 2. 永远不要以明文形式存储
   * 3. 在 API 响应中排除此字段 (使用 @Exclude() 装饰器)
   *
   * 示例安全配置：
   * @Column({ select: false }) // 查询时默认不包含此字段
   */
  @Column({ nullable: false })
  @Exclude()
  password: string;

  /**
   * 一对多关系：用户 -> 日志记录
   *
   * @OneToMany() 装饰器定义一对多关系：
   * - 一个用户可以有多条日志记录
   * - () => Logs: 延迟加载目标实体类型，避免循环依赖
   * - logs => logs.user: 指定关系的反向引用字段
   *
   * 关系的工作原理：
   * 1. 在 Logs 表中会有一个 user_id 外键字段
   * 2. TypeORM 会自动处理关联查询
   * 3. 可以通过 user.logs 访问该用户的所有日志
   *
   * 查询示例：
   * const userWithLogs = await userRepository.findOne({
   *   where: { id: 1 },
   *   relations: ['logs']
   * });
   */
  @OneToMany(() => Logs, (logs) => logs.user)
  logs: Logs[];

  /**
   * 多对多关系：用户 <-> 角色
   *
   * @ManyToMany() 装饰器定义多对多关系：
   * - 一个用户可以拥有多个角色
   * - 一个角色可以分配给多个用户
   *
   * @JoinTable() 装饰器的作用：
   * - 指定中间表的配置
   * - name: "users_roles" 设置中间表名称
   * - 只需要在关系的一侧使用 @JoinTable()，通常是主导方
   *
   * 数据库结构：
   * 1. users 表：存储用户信息
   * 2. roles 表：存储角色信息
   * 3. users_roles 表：存储用户-角色关联关系
   *    - user_id: 外键，指向 users.id
   *    - role_id: 外键，指向 roles.id
   *
   * 使用示例：
   * const userWithRoles = await userRepository.findOne({
   *   where: { id: 1 },
   *   relations: ['roles']
   * });
   */
  @ManyToMany(() => Roles, (roles) => roles.users)
  @JoinTable({ name: "users_roles" })
  roles: Roles[];

  @OneToOne(() => Profile, (profile) => profile.user)
  profile: Profile;

  @AfterInsert()
  async afterInsert() {
    console.log(`用户 ${this.username} 插入成功`);
  }

  @AfterRemove()
  async afterRemove() {
    console.log(`用户 ${this.username} 删除成功`);
  }
}
